using System;
using System.Linq;
using System.Collections.Generic;
using System.Data.Objects;
using System.Data.Metadata.Edm;

namespace JingQiao.Ads.Infrastructure.Data.EF
{
    using Domain.Model;

    public partial class AdsContext : IContext
    {
        #region IContext Members

        public void SetChanges<TEntity>(TEntity item) where TEntity : class, new()
        {
            throw new NotImplementedException();
        }

        private readonly static IDictionary<string, string> EntitySetNames = new Dictionary<string, string>(10);

        public string GetEntitySetName(Type entitySetType)
        {
            lock (EntitySetNames)
            {
                if (EntitySetNames.ContainsKey(entitySetType.FullName))
                {
                    return EntitySetNames[entitySetType.FullName];
                }

                var container = MetadataWorkspace.GetEntityContainer(DefaultContainerName, DataSpace.CSpace);
                var entitySetName = (from meta in container.BaseEntitySets
                                     where meta.BuiltInTypeKind == BuiltInTypeKind.EntitySet &&
                                     meta.ElementType.Name == entitySetType.Name.Substring(1)
                                     select meta.Name).First();
                EntitySetNames.Add(entitySetType.FullName, entitySetName);

                return entitySetName;
            }
        }

        public virtual IQueryable<TEntity> GetQueryable<TEntity>()
        {
            var entitySetName = GetEntitySetName(typeof(TEntity));
            return GetQueryable<TEntity>(entitySetName);
        }

        private string SearchQuery { get; set; }
        public void SetSearchQuery(string query)
        {
            SearchQuery = query;
        }

        public void Insert<TEntity>(TEntity entity)
        {
            var entitySetName = GetEntitySetName(typeof(TEntity));
            this.AddObject(entitySetName, entity);
        }

        public void InsertAll<TEntity>(IEnumerable<TEntity> instances)
        {
            var entitySetName = GetEntitySetName(typeof(TEntity));
            foreach (var entity in instances)
            {
                AddObject(entitySetName, entity);
            }
        }

        public void Delete<TEntity>(TEntity entity)
        {
            this.DeleteObject(entity);
        }

        public void DeleteAll<TEntity>(IEnumerable<TEntity> instances)
        {
            foreach (var entity in instances)
            {
                this.Delete(entity);
            }
        }

        private IQueryable<TEntity> GetQueryable<TEntity>(string queryString)
        {
            return ApplyDataLoadOptions<TEntity>(queryString);
        }

        private ObjectQuery<TEntity> ApplyDataLoadOptions<TEntity>(string queryString)
        {
            var query = CreateQuery<TEntity>(queryString);

            //if (LoadOptions != null)
            //{
            //    var members = LoadOptions.GetPreloadedMembers<TEntity>();

            //    foreach (var member in members)
            //    {
            //        query = query.Include(member.Name);
            //    }
            //}

            return query;
        }
        #endregion

        #region IUnitOfWork Members

        private bool _isDisposed;

        public void Commit()
        {
            this.Commit(CommitOption.ClientWins);
        }

        public void Commit(CommitOption commitOption)
        {
            this.SubmitChanges();
        }

        public void SubmitChanges()
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            this.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);
        }

        public void RollbackChanges()
        {
        }

        protected override void Dispose(bool disposing)
        {
            if (!_isDisposed)
            {
                _isDisposed = true;
            }

            base.Dispose(disposing);
        }

        #endregion
    }
}
